package thread;

/**
 * 多线程的意义：
 * 通过代码感受，单个线程和多个线程之间，执行速度的差别
 */
public class ThreadDemo12 {
    public static void main(String[] args) {
        // 假设当前有两个变量，需要把两个变量各自自增 1000w 次，（典型的 CPU 密集的场景）
        // 1.可以一个线程，先对 a 自增，然后在对 b 自增
        // 2.还可以两个线程，分别对 a,b 自增
//        serial();
        concurrency();
    }

    // 串行执行，一个线程完成
    public static void serial() {
        // 为了衡量代码的执行速度，加上一个计时的操作
        // currentTimeMillis 获取到当前系统的 ms 级时间戳
        long beg = System.currentTimeMillis();

        /*
        像这种衡量执行时间的代码，让它跑的久一点，误差就小
        因为线程调度自身也是有时间开销的，运算的任务量越大，线程调度的开销相比之下就不明显了，从而就忽略不计了
         */
        long a = 0;
        for (long i = 0; i < 100_0000_0000L; i++) { // 后缀加 L 表示是 long 类型
            a++;
        }
        long b = 0;
        for (long i = 0; i < 100_0000_0000L; i++) {
            b++;
        }

        // 结束的时候也加一个时间戳
        long end = System.currentTimeMillis();
        System.out.println("执行时间：" + (end - beg) + "ms");
    }

    public static void concurrency() {
        // 使用两个线程分别完成自增
        Thread t1 = new Thread(() -> {
            long a = 0;
            for (long i = 0; i < 100_0000_0000L; i++) { // 后缀加 L 表示是 long 类型
                a++;
            }
        });
        Thread t2 = new Thread(() -> {
            long b = 0;
            for (long i = 0; i < 100_0000_0000L; i++) { // 后缀加 L 表示是 long 类型
                b++;
            }
        });

        // 开始计时
        long beg = System.currentTimeMillis();
        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join(); // 此处的 join 就是让当前的 main 线程来等待 t 线程执行结束（等待 t 的 run 执行完）
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 结束计时
        long end = System.currentTimeMillis();
        System.out.println("执行时间：" + (end - beg) + "ms");
    }
}
